﻿using Adnc.Application.Shared.Services;
using Adnc.Application.Shared.WeChat;
using Adnc.Infra.Caching;
using Adnc.Infra.Helper;
using Adnc.Infra.IRepositories;
using Adnc.Shared.ConfigModels;
using Adnc.Shared.Consts;
using Adnc.Shared.RpcServices.Rtos.Sys;
using Adnc.Shared.RpcServices.Services;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using WYT.Usr.Application.Contracts.Dtos;
using WYT.Usr.Application.Contracts.Dtos.User;
using WYT.Usr.Application.Contracts.Services;
using WYT.Usr.Repository.Entities;

namespace WYT.Usr.Application.Services
{
    /// <summary>
    /// 用户登录与注册
    /// </summary>
    public class AccountAppService : AbstractAppService, IAccountAppService
    {
        private readonly JwtConfig _jwtConfig;

        private readonly IEfRepository<User> _userRepository;

        private readonly IEfRepository<ShareLinks> _shareLinksRepository;

        private readonly IEfRepository<UserRelation> _userRelationRepository;

        private readonly ISysRpcService _sysRpcService;

        private readonly IRedisProvider _redisProvider;

        private readonly WeChatService _weChatService;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="userRepository"></param>
        /// <param name="userRelationRepository"></param>
        /// <param name="shareLinksRepository"></param>
        /// <param name="jwtConfig"></param>
        /// <param name="sysRpcService"></param>
        /// <param name="redisProvider"></param>
        /// <param name="weChatService"></param>
        public AccountAppService(
            IEfRepository<User> userRepository,
            IEfRepository<UserRelation> userRelationRepository,
            IEfRepository<ShareLinks> shareLinksRepository,
            IOptions<JwtConfig> jwtConfig,
            ISysRpcService sysRpcService,
            IRedisProvider redisProvider,
            WeChatService weChatService)
        {
            _userRepository = userRepository;
            _userRelationRepository = userRelationRepository;
            _shareLinksRepository = shareLinksRepository;
            _jwtConfig = jwtConfig.Value;
            _sysRpcService = sysRpcService;
            _redisProvider = redisProvider;
            _weChatService = weChatService;
        }

        /// <summary>
        /// 用户刷新Token
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public async Task<AppSrvResult<UserTokenInfoDto>> RefreshAccessTokenAsync(UserRefreshTokenDto input)
        {
            var userId = JwtTokenHelper.GetUserId(input.RefreshToken);
            if (userId == 0)
                return Problem(HttpStatusCode.NotFound);
            else
            {
                var user = await _userRepository.FindAsync(userId);
                if (user == null)
                    return Problem(HttpStatusCode.NotFound);
                else
                    return new UserTokenInfoDto
                    {
                        Token = JwtTokenHelper.CreateAccessToken(_jwtConfig, user),
                        RefreshToken = JwtTokenHelper.CreateRefreshToken(_jwtConfig, user)
                    };
            }
        }

        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<AppSrvResult<UserTokenInfoDto>> LoginAsync(UserParaDto input)
        {
            var sessionRepone = await  _weChatService.GetJsCode2Session(input.AppletCode);
            var oauthRepone = await _weChatService.GetOAuth2AccessToken(input.GZHCode);         

            var user = await _userRepository.FindAsync(x => x.GongZongHaoOpenID == oauthRepone.OpenId || x.AppletOpenID == sessionRepone.OpenId);
            if (user == null)
            {
                user = new User
                {
                    Id = IdGenerater.GetNextId(),
                    Tel = String.Empty,
                    AppletOpenID = sessionRepone.OpenId,
                    GongZongHaoOpenID = oauthRepone.OpenId,
                    SuperiorUser = WYTConst.defaultSuperior,
                    CreatTime = DateTime.Now,
                    LastLoginTime = DateTime.Now,
                    Grade = 1
                };

                var reslations = new List<UserRelation>();
                if (input.SuperiorUser == 0)
                {
                    reslations.Add(new UserRelation
                    {
                        Id = IdGenerater.GetNextId(),
                        Ancestor = WYTConst.defaultSuperior,
                        Descendant = user.Id,
                        Level = 1,
                        CreateTime = DateTime.Now
                    });
                }
                else
                {
                    var sup = await _userRepository.FindAsync(x => x.Id == input.SuperiorUser);
                    if (sup == null)
                    {
                        reslations.Add(new UserRelation
                        {
                            Id = IdGenerater.GetNextId(),
                            Ancestor = WYTConst.defaultSuperior,
                            Descendant = user.Id,
                            Level = 1,
                            CreateTime = DateTime.Now
                        });
                    }
                    else
                    {
                        user.SuperiorUser = sup.Id;
                        reslations.Add(new UserRelation()
                        {
                            Id = IdGenerater.GetNextId(),
                            Ancestor = sup.Id,
                            Descendant = user.Id,
                            Level = 1,
                            CreateTime = DateTime.Now
                        });
                        var rel = await _userRelationRepository.Where(x => x.Descendant == sup.Id).ToListAsync();
                        foreach (var item in rel)
                        {
                            reslations.Add(new UserRelation()
                            {
                                Id = IdGenerater.GetNextId(),
                                Ancestor = item.Ancestor,
                                Descendant = user.Id,
                                Level = item.Level + 1,
                                CreateTime = DateTime.Now
                            });
                        }
                    }

                }

                await _userRepository.InsertAsync(user);
                await _userRelationRepository.InsertRangeAsync(reslations);
            }
            else
            {
                user.LastLoginTime = DateTime.Now;
                await _userRepository.UpdateAsync(user, UpdatingProps<User>(x => x.LastLoginTime));
            }    

            if (string.IsNullOrEmpty(user.GongZongHaoOpenID) || string.IsNullOrEmpty(user.AppletOpenID))
            {
                user.GongZongHaoOpenID = oauthRepone.OpenId;
                user.AppletOpenID = sessionRepone.OpenId;
                await _userRepository.UpdateAsync(user,UpdatingProps<User>(x => x.AppletOpenID,x => x.GongZongHaoOpenID));
            }
            return new UserTokenInfoDto
            {
                Token = JwtTokenHelper.CreateAccessToken(_jwtConfig, user),
                RefreshToken = JwtTokenHelper.CreateRefreshToken(_jwtConfig, user)
            };
        }

        /// <summary>
        /// 发送验证码
        /// </summary>
        /// <param name="telePhone"></param>
        /// <returns></returns>
        public async Task<AppSrvResult> SendSms(string telePhone)
        {
            var user = await _userRepository.FindAsync(x => x.Tel == telePhone);
            if (user == null)
                return Problem(HttpStatusCode.BadRequest, "用户不存在，请先使用微信登录注册。");

            var data = await _redisProvider.StringGetAsync("dlr" + user.Id);
            if (data.IsNull())
            {
                Random rad = new Random();
                int code = rad.Next(1000, 10000);
                string smsCodeTemp = "{\"code\":\"" + code + "\"}";
                var smsResponse = await _sysRpcService.SendSms(new SendSmsRto { Tel = user.Tel, Temp = "SMS_175536463", TempParam = smsCodeTemp });
                if (!smsResponse.IsSuccessStatusCode)
                    return Problem(HttpStatusCode.BadRequest, "服务异常");
                if (!smsResponse.Content)
                    return Problem(null, "验证码发送失败");

                _ = await _redisProvider.StringSetAsync("dlc" + user.Id, code.ToString(), new TimeSpan(0, 5, 0));
                _ = await _redisProvider.StringSetAsync("dlr" + user.Id, "1", new TimeSpan(0, 1, 0));
            }
            else
                return Problem(null, "一分钟只能发送一次短信");
            return AppSrvResult();
        }

        /// <summary>
        /// 手机号登录
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<AppSrvResult<UserTokenInfoDto>> TelLoginAsync(TelLoginDto input)
        {
            var user = await _userRepository.FindAsync(x => x.Tel == input.Tel);
            if (user == null)
                return Problem(HttpStatusCode.BadRequest, "参数错误");

            var data = await _redisProvider.StringGetAsync("dlc" + user.Id);
            if (data.IsNull() || data != input.Code)
                return Problem(null, "验证码不正确或者已过期");

            await _redisProvider.KeyDelAsync("dlc" + user.Id);
            return new UserTokenInfoDto
            {
                Token = JwtTokenHelper.CreateAccessToken(_jwtConfig, user),
                RefreshToken = JwtTokenHelper.CreateRefreshToken(_jwtConfig, user)
            };
        }


        /// <summary>
        /// 获取小程序码
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<AppSrvResult<string>> GetWxaCode(WxaCodeDto input)
        {
            using var ms = new MemoryStream();
            var links = new ShareLinks
            {
                Id = IdGenerater.GetNextId(),
                Path = input.Scene,
                CreateTime = DateTime.Now,
            };
            await _shareLinksRepository.InsertAsync(links);
            var response = await _weChatService.GetQrCode(links.Id.ToString(), input.Page);
            if (response.IsSuccessful())
                return Convert.ToBase64String(response.RawBytes);
            else
            {
                if (response.ErrorCode == 41030)
                    return Problem(null, "后台小程序配置的APPID和APPSECRET对应的小程序未发布上线,或者page没有发布");
                else if (response.ErrorCode == 40001)
                    return Problem(null, "微信小程序access_token已过期");
                else
                    return Problem(null, $"获取小程序码失败,ErrorCode:{response.ErrorCode}");
            }
        }

        /// <summary>
        /// 获取分享路径
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<AppSrvResult<string>> GetSharePath(long input)
        {
            var data = await _shareLinksRepository.FindAsync(input);
            if (data == null)
                return Problem(HttpStatusCode.NotFound, "参数错误");
            return data.Path;
        }

        /// <summary>
        /// 获取用户token,仅开发用
        /// </summary>
        /// <param name="userId"></param>
        /// <returns></returns>
        public async Task<AppSrvResult<UserTokenInfoDto>> LoginAsync(long userId)
        {
            var user = await _userRepository.FindAsync(userId);
            return new UserTokenInfoDto
            {
                Token = JwtTokenHelper.CreateAccessToken(_jwtConfig, user),
                RefreshToken = JwtTokenHelper.CreateRefreshToken(_jwtConfig, user)
            };
        }
    }
}
